#Copyright (C) Nial Peters 2013
#
#This file is part of pydoas.
#
#pydoas is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#pydoas is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with pydoas.  If not, see <http://www.gnu.org/licenses/>.
"""
The input/output module deals with loading and saving spectrum files. It uses a 
set of plugins to allow it to open and save different formats of spectra.
"""
import os
import glob

import doas.plugins
import doas.spec

#global dict of plugins which have been registered - registration should 
#normally occur when the plugin file is imported
_spectrum_plugins = {}


def register(plugin):
    """
    Registers a plugin with pydoas. This should be called when the plugin is
    imported.
    """
    _spectrum_plugins[plugin.name] = plugin


def list_plugins():
    """
    Returns a list of names of currently registered plugins.
    """
    return  _spectrum_plugins.keys()


def _load_all_plugins():
    """
    Imports all the plugins in the doas.plugins package. This function gets 
    called in doas.__init__ and should not need to be called manually.
    """
    # get the path where all the plugin modules should live
    plugins_directory = doas.plugins.__path__[0]
    
    cur_dir = os.getcwd()
    os.chdir(plugins_directory)
    
    for plugin_file in glob.glob("*.py"):
        __import__("doas.plugins."+plugin_file.rstrip(".py"), 
                   fromlist=["doas.plugins"], globals=globals(), locals=locals())
        
    #return to the old working dir
    os.chdir(cur_dir)


def get_loadable_formats():
    """
    Returns a list of spectrum file formats which can be loaded with the 
    currently registered plugins.
    """
    fmts = []
    for plugin in _spectrum_plugins.values():
        if hasattr(plugin, 'load'):
            fmts.append(plugin.name)
    return fmts


def get_saveable_formats():
    """
    Returns a list of spectrum file formats which can be saved to using the 
    currently registered plugins.
    """
    fmts = []
    for plugin in _spectrum_plugins.values():
        if hasattr(plugin, 'save'):
            fmts.append(plugin.name)
    return fmts


class UnableToLoad(IOError):
    """
    Exception raised when a spectrum file cannot be loaded.
    """
    pass
 
     
class SpectrumIO:
    
    def __init__(self):
        """
        SpectrumIO objects are used for loading and saving spectrum files in a 
        variety of formats. They are the main interface to pydoas's plugins 
        system. Note that once you have used a SpectrumIO instance to load one
        type of spectrum, you cannot use it to open a different kind of spectrum.
        """
        self.__active_plugin = None

    
    def save(self, spectrum, filename, format):
        """
        Save a spectrum object in filename with the specified format. The format
        must be available from the registered plugins i.e. it should appear the 
        list returned by get_saveable_formats().
        """
        assert isinstance(spectrum, doas.spec.Spectrum), ("spectrum argument "
                                                          "must be a Spectrum "
                                                          "object.")
        
        if not format in get_saveable_formats():
            raise ValueError("No plugin registered that supports saving in "
                             "\'%s\' format."%format)
        
        plugin = _spectrum_plugins[format]
        
        plugin.save(spectrum, filename)
        
            
    def load(self, filename):
        """
        Loads the specified spectrum file, returning a Spectrum object. If the 
        file cannot be loaded then raises UnableToLoad.
        
        Note that once you have used a SpectrumIO instance to load one
        type of spectrum, you cannot use it to open a different kind of spectrum.
        """
        try:
            with open(filename, 'r') as ifp:
                
                if self.__active_plugin is None:           
                    for plugin in _spectrum_plugins.values():
                        if plugin.test(ifp):
                            self.__active_plugin = plugin
                            ifp.seek(0)
                            break
                        ifp.seek(0)
                    
                    if self.__active_plugin is None:
                        print "No plugin registered for file "+filename
                        raise UnableToLoad("No plugin registered for file "+filename)
                else:
                    if not self.__active_plugin.test(ifp):
                        print "Wrong file type:"+filename
                        raise UnableToLoad("Wrong file type:"+filename)
                    ifp.seek(0)
                
                try:
                    s = self.__active_plugin.load(ifp)
                except Exception,e:
                    print "Failed to load "+filename+":"+str(e.args)
                    raise UnableToLoad("Failed to load "+filename+":"+str(e.args))
        except IOError,e:
            raise UnableToLoad(*e.args)        
            
        return s
        
        
                
        